#include <iostream>
#include <string>
using namespace std;

int test1()//string类基本用法
{
    string s1;
    string s2("Hello World!");
    string s3="Hello World!";   //拷贝构造
    string s4(s2, 3, 16);//从s2中的下标位置[3]开始拷贝16个字符，字符不够遇到'\0'结束
    string s5(s2, 3);   //不给第三个参数默认给 size_t npos=-1;无符号整数的最大值，相当于全拷贝
    string s6("Hello World",4);//拷贝字符串中4个字符
    string s7(10,'*');//拷贝10个'*'

    cout << "s4: " << s4 << endl;
    cout << "s5: " << s5 << endl;
    cout << "s6: " << s6 << endl;
    cout << "s7: " << s7 << endl;
    for(size_t i=0; i<s2.size(); ++i)
    {
        cout << s2[i];
    }
    cout << endl;
    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



int test2()//string类中的函数调用
{
    string s1("Hello World!");
    cout << s1.size() << endl;//字符长度
    cout << s1.length() << endl;//同上，因为历史发展改写成了size
    cout << s1.max_size() << endl;//最大能存放几个字符,编译器不一样有区别
    cout << s1.capacity() << endl;//扩容的空间大小，按照编译器扩容算法
    //不常用
    s1.push_back('!');//在字符串后插入一个字符
    cout << s1 << endl;
    s1.append("world");//在字符串后插入一串字符
    cout << s1 <<endl;
    //字符串插入重载
    s1+="!!!";
    cout << s1 <<endl;

    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————




int test3()//reserve和resize的区别
{
    //扩容
    string s1=("Hello World");
    s1.reserve(100);//reserve改变的是空间大小 扩容11+100
    s1.reserve(50);  //调整容量为 50，由于调整的容量小于已有空间容量，故容量不会减小
    cout << s1.size() << endl;
    cout << s1.capacity() << endl;//改变空间s1.size+100

    //扩容+初始化
    string s2=("Hello World");
    s2.resize(100,'x');     //resize两个都改变,把字符数组里添加满100个长度的'x'字符，默认为'\0'
    cout << s2.size() << endl;//s2.size=100
    cout << s2.capacity() << endl;//11+100

    //不会缩容 只会删除数据
    s1.resize(5);
    cout << s1 <<endl;
    cout << s1.size() << endl;//改变
    cout << s1.capacity() << endl;//不变 依旧是扩容后的大小

    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



void func(const string& s)
{
    //const_iterator：只能遍历、读容器it的数据  const_reverse_iterator同理
    string::const_iterator it=s.begin();//begin 返回第一个位置的地址
    while(it != s.end())//end是最后一个 '\0'
    {
        cout << *it << " ";
        ++it;
    }
    cout <<endl;
}
int test4()//迭代器
{
    string s1("Hello World");
    //iterator：可以遍历、读写容器it的数据 reverse_iterator同理
    //string::iterator it=s1.begin();//begin 返回第一个位置的地址t
    auto it=s1.begin();
    while(it != s1.end())//end是最后一个 '\0'
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    //string::reverse_iterator rit=s1.rbegin();//rbegin在字符串最后一个字符('\0'前面一个)
    auto rit=s1.rbegin();//auto 自动识别类型：迭代器
    while(rit != s1.rend())//rend在字符串头
    {
        cout << *rit << " ";
        ++rit;  //从rbegin走到rend  反向迭代器
    }
    cout << endl;
    func(s1);

    cout << s1.at(0)<< endl;//.at(0)访问第0个字符 s1.at(100)和s1.[100]相比，at越界访问不会报错 会抛异常
    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



int test5()//insert插入和erase删除字符
{
    string s1("Hello World");
    //不推荐经常使用 能少用就少用 它们都要挪动数据 效率低下
    s1.insert(0,"012");//在0位置插入字符串，不会插入'\0'
    cout << s1 << endl;
    //s1.insert(3," ");//在下标3处插入空格
    s1.insert(s1.begin()+3,' ');//在下标3处插入空格
    cout << s1 << endl;
    //s1.erase(0,3);//删除下标0后的三个字符
//    s1.erase(s1.begin()+1);//删除下标1处字符
    s1.erase(3);//删除下标3后的所有字符
    cout << s1 << endl;

    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



int test6()//find()查找字符下标，replace(pos，char)替换pos处的字符
{
    string s1("Hello  World");
    //find(char,pos)在pos位置找char，缺省则pos为0
    size_t pos=s1.find(' ');//找到返回下标位置，否则返回-1
    while(pos!=string::npos) //npos默认为-1 static const类型
    {
        s1.replace(pos,1,"%20");//替换pos位置的一个字符，替换成%20
        pos =s1.find(' ',pos);//从pos位置开始查找
    }
    cout << s1 << endl;
    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



int test7()//string类型交换swap
{
    string s1="xxxxx";
    string s2="ooooo";
    cout << s1 << endl << s2 <<endl;
//    swap(s1,s2);
    s1.swap(s2);//直接修改s1,s2指向，更高效
    cout << s1 << endl << s2 <<endl;

    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



int test8()//c_str：C语言方式输出字符串(遇'\0'停止
{
    string s1="xxxxx";
    cout << s1 << endl;//指针类型打印 char*
    cout << s1.c_str() << endl;//字符串打印，算是常量
    cout << (void*)s1.c_str() << endl;//且s1.c_str是一个地址
    s1+='\0';
    s1+='\0';
    s1+="12345";
    cout <<"修改后："<< endl;
    cout << s1 << endl;//有多少内容就输出多少，也会输出'\0'
    cout << s1.c_str() << endl;//遇到'\0'停止输出
    //为了兼容C语言字符串调用 例如：
    /*
    string filename("/Users/wen_lty/code/Yakitori_Hello/Cpp_string/CMakeLists.txt");
    FILE* fout=fopen(filename.c_str(),"r");
    if(fout== nullptr)
        perror("Open Fail");
    char ch=fgetc(fout);
    while(ch != EOF)
    {
        cout << ch;
        ch=fgetc(fout);
    }
    fclose(fout);
    */

}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



int test9()//substr()截取字符段和find_first_of()查找每个字符
{
    string str="test.cpp.zip";
    size_t pos=str.rfind('.');//反向查找字符下标
    string suffix=str.substr(pos,str.size()-pos);//从pos位置开始截取n个字符
    cout << suffix << endl;
    cout << str << endl;

    //size_t found=str.find_first_not_of("esp");//顺着找除e s p以外的字符的下标值
    size_t found=str.find_first_of("esp");//顺着找到e s p中其中一个的下标值
    //size_t found=str.find_last_not_of("esp");//倒着找除e s p以外的字符的下标值
    size_t last_found=str.find_last_of("esp");//倒着找到e s p中其中一个的下标值
    while(found!=string::npos)
    {
        str[found]='*';
        found=str.find_first_of("esp",found);
    }
    cout << str << endl;

    return 0;
}
int main()
{
//    test1();
//    test2();
//    test3();
//    test4();
//    test5();
//    test6();
//    test7();
//    test8();
    test9();
    return 0;
}
